package com.bzchao.doublecamera.handler;

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.SoundPool;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import com.bzchao.camera.encode.MediaAudioEncoder;
import com.bzchao.camera.encode.MediaEncoder;
import com.bzchao.camera.encode.MediaMuxerWrapper;
import com.bzchao.camera.encode.MediaVideoBufferEncoder;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

class CameraThread extends Thread {
    private static final String TAG = "CameraThread";
    private static final boolean DEBUG = true;
    private final Object mSync = new Object();
    private final Class<? extends CameraHandler> mHandlerClass;
    private final WeakReference<Activity> mWeakParent;
    private final int mWidth;
    private final int mHeight;
    private boolean mIsPreviewing;
    private boolean mIsRecording;
    /**
     * shutter sound
     */
    private SoundPool mSoundPool;
    private int mSoundId;
    private CameraHandler mHandler;


    /**
     * muxer for audio/video recording
     */
    private MediaMuxerWrapper mMuxer;
    private MediaVideoBufferEncoder mVideoEncoder;

    private final MediaEncoder.MediaEncoderListener mMediaEncoderListener = new MediaEncoder.MediaEncoderListener() {
        @Override
        public void onPrepared(final MediaEncoder encoder) {
            Log.i(TAG, "onPrepared:encoder=" + encoder);
            mIsRecording = true;
        }

        @Override
        public void onStopped(final MediaEncoder encoder) {
            Log.i(TAG, "onStopped:encoder=" + encoder);
            mIsRecording = false;
        }
    };

    /**
     * @param clazz  Class extends CameraHandler
     * @param parent parent Activity
     * @param width
     * @param height
     */
    CameraThread(final Class<? extends CameraHandler> clazz,
                 final Activity parent, final int width, final int height) {

        super("CameraThread");
        mHandlerClass = clazz;
        mWidth = width;
        mHeight = height;
        mWeakParent = new WeakReference<>(parent);
        loadShutterSound(parent);
    }

    @Override
    protected void finalize() throws Throwable {
        Log.i(TAG, "CameraThread#finalize");
        super.finalize();
    }

    public CameraHandler getHandler() {
        Log.v(TAG, "getHandler:");
        synchronized (mSync) {
            if (mHandler == null)
                try {
                    mSync.wait();
                } catch (final InterruptedException e) {
                }
        }
        return mHandler;
    }

    public int getWidth() {
        synchronized (mSync) {
            return mWidth;
        }
    }

    public int getHeight() {
        synchronized (mSync) {
            return mHeight;
        }
    }

    public MediaVideoBufferEncoder getmVideoEncoder() {
        return mVideoEncoder;
    }

    public boolean isCameraOpened() {
        synchronized (mSync) {
            //TODO 更改过
            // return mUVCCamera != null;
            return (mMuxer != null);
        }
    }

    public boolean isPreviewing() {
        synchronized (mSync) {
            return mIsPreviewing;
        }
    }

    public boolean isRecording() {
        synchronized (mSync) {
            return (mMuxer != null);
        }
    }


    public void handleClose() {
        if (DEBUG) {
            Log.v(TAG, "handleClose:");
        }
        handleStopRecording();
    }

    public void handleStartPreview(final Object surface) {
        if (DEBUG) {
            Log.v(TAG, "handleStartPreview:");
        }
        synchronized (mSync) {
            mIsPreviewing = true;
        }
    }

    public void handleStopPreview() {
        if (DEBUG) {
            Log.v(TAG, "handleStopPreview:");
        }
        if (mIsPreviewing) {
            synchronized (mSync) {
                mIsPreviewing = false;
                mSync.notifyAll();
            }
        }
        if (DEBUG) {
            Log.v(TAG, "handleStopPreview:finished");
        }
    }


    public void handleStartRecording() {
        Log.v(TAG, "handleStartRecording:");
        try {
            if (mMuxer != null) return;
            final MediaMuxerWrapper muxer = new MediaMuxerWrapper(".mp4");    // if you record audio only, ".m4a" is also OK.
            MediaVideoBufferEncoder videoEncoder = new MediaVideoBufferEncoder(muxer, getWidth(), getHeight(), mMediaEncoderListener);

            if (true) {
                // for audio capturing
                new MediaAudioEncoder(muxer, mMediaEncoderListener);
            }
            muxer.prepare();
            Toast.makeText(mWeakParent.get(), "准备完成", Toast.LENGTH_LONG).show();
            Log.i("muxer.prepare()", "准备完成");
            muxer.startRecording();

            synchronized (mSync) {
                mMuxer = muxer;
                mVideoEncoder = videoEncoder;
            }
        } catch (final IOException e) {
            Log.e(TAG, "startCapture:", e);
        }
    }

    public void handleStopRecording() {
        Log.v(TAG, "handleStopRecording:mMuxer=" + mMuxer);
        final MediaMuxerWrapper muxer;
        synchronized (mSync) {
            muxer = mMuxer;
            mMuxer = null;
            mVideoEncoder = null;
        }
        if (muxer != null) {
            muxer.stopRecording();
        }
    }

    public void handleUpdateMedia(final String path) {
        Log.v(TAG, "handleUpdateMedia:path=" + path);
        final Activity parent = mWeakParent.get();
        final boolean released = (mHandler == null) || mHandler.isReleased();
        if (parent != null && parent.getApplicationContext() != null) {
            try {
                Log.i(TAG, "MediaScannerConnection#scanFile");
                MediaScannerConnection.scanFile(parent.getApplicationContext(), new String[]{path}, null, null);
            } catch (final Exception e) {
                Log.e(TAG, "handleUpdateMedia:", e);
            }
            if (released || parent.isDestroyed())
                handleRelease();
        } else {
            Log.w(TAG, "MainActivity already destroyed");
            // give up to add this movie to MediaStore now.
            // Seeing this movie on Gallery app etc. will take a lot of time.
            handleRelease();
        }
    }

    public void handleRelease() {
        Log.v(TAG, "handleRelease:mIsRecording=" + mIsRecording);
        handleClose();
        if (!mIsRecording) {
            mHandler.release();
            Looper.myLooper().quit();
        }
        Log.v(TAG, "handleRelease:finished");
    }

    /**
     * prepare and load shutter sound for still image capturing
     */
    @SuppressWarnings("deprecation")
    private void loadShutterSound(final Context context) {
        // get system stream type using reflection
        int streamType;
        try {
            final Class<?> audioSystemClass = Class.forName("android.media.AudioSystem");
            final Field sseField = audioSystemClass.getDeclaredField("STREAM_SYSTEM_ENFORCED");
            streamType = sseField.getInt(null);
        } catch (final Exception e) {
            streamType = AudioManager.STREAM_SYSTEM;    // set appropriate according to your app policy
        }
        if (mSoundPool != null) {
            try {
                mSoundPool.release();
            } catch (final Exception e) {
            }
            mSoundPool = null;
        }
        // load shutter sound from resource
        mSoundPool = new SoundPool(2, streamType, 0);
        // mSoundId = mSoundPool.load(context, R.raw.camera_click, 1);
    }

    /**
     * createHandler 时start
     */
    @Override
    public void run() {
        Looper.prepare();
        CameraHandler handler = null;
        try {
            final Constructor<? extends CameraHandler> constructor = mHandlerClass.getDeclaredConstructor(CameraThread.class);
            handler = constructor.newInstance(this);
        } catch (Exception e) {
            Log.w(TAG, e);
        }
        if (handler != null) {
            synchronized (mSync) {
                mHandler = handler;
                mSync.notifyAll();
            }
            Looper.loop();
            if (mSoundPool != null) {
                mSoundPool.release();
                mSoundPool = null;
            }
            if (mHandler != null) {
                mHandler.release();
            }
        }
        synchronized (mSync) {
            mHandler = null;
            mSync.notifyAll();
        }
    }

    public Object getmSync() {
        return mSync;
    }
}